package com.summerbird.mallchat.common.user.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.summerbird.mallchat.common.chat.domain.entity.RoomFriend;
import com.summerbird.mallchat.common.chat.service.ChatService;
import com.summerbird.mallchat.common.chat.service.RoomService;
import com.summerbird.mallchat.common.chat.service.adapter.MessageAdapter;
import com.summerbird.mallchat.common.common.annotation.RedissonLock;
import com.summerbird.mallchat.common.common.domain.vo.req.CursorPageBaseReq;
import com.summerbird.mallchat.common.common.domain.vo.req.PageBaseReq;
import com.summerbird.mallchat.common.common.domain.vo.resp.CursorPageBaseResp;
import com.summerbird.mallchat.common.common.domain.vo.resp.PageBaseResp;
import com.summerbird.mallchat.common.common.event.UserApplyEvent;
import com.summerbird.mallchat.common.common.utils.AssertUtil;
import com.summerbird.mallchat.common.common.utils.RequestHolder;
import com.summerbird.mallchat.common.user.dao.UserApplyDao;
import com.summerbird.mallchat.common.user.dao.UserDao;
import com.summerbird.mallchat.common.user.dao.UserFriendDao;
import com.summerbird.mallchat.common.user.domain.entity.User;
import com.summerbird.mallchat.common.user.domain.entity.UserApply;
import com.summerbird.mallchat.common.user.domain.entity.UserFriend;
import com.summerbird.mallchat.common.user.domain.vo.req.friend.FriendApplyReq;
import com.summerbird.mallchat.common.user.domain.vo.req.friend.FriendApproveReq;
import com.summerbird.mallchat.common.user.domain.vo.req.friend.FriendCheckReq;
import com.summerbird.mallchat.common.user.domain.vo.resp.friend.FriendApplyResp;
import com.summerbird.mallchat.common.user.domain.vo.resp.friend.FriendCheckResp;
import com.summerbird.mallchat.common.user.domain.vo.resp.friend.FriendResp;
import com.summerbird.mallchat.common.user.domain.vo.resp.friend.FriendUnreadResp;
import com.summerbird.mallchat.common.user.service.FriendService;
import com.summerbird.mallchat.common.user.service.adapter.FriendAdapter;
import com.summerbird.mallchat.common.websocket.service.WebSocketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.summerbird.mallchat.common.user.domain.enums.ApplyStatusEnum.WAIT_APPROVAL;

@Slf4j
@Service
public class FriendServiceImpl implements FriendService {

    @Autowired
    private RoomService roomService;
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserFriendDao userFriendDao;
    @Autowired
    private UserApplyDao userApplyDao;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    @Autowired
    private WebSocketService webSocketService;
    @Autowired
    private ChatService chatService;

    @Override
    public CursorPageBaseResp<FriendResp> friendList(Long uid, CursorPageBaseReq request) {
        // 找到所有自己的好友关系表
        CursorPageBaseResp<UserFriend> friendPage = userFriendDao.getFriendPage(uid, request);
        if(CollectionUtil.isEmpty(friendPage.getList())){
            return CursorPageBaseResp.empty();
        }
        // 获取好友列表
        List<Long> friendIdsList = friendPage.getList()
                .stream()
                .map(UserFriend::getFriendUid)
                .collect(Collectors.toList());
        List<User> userList = userDao.listByIds(friendIdsList);
        // 组装返回数据
        return CursorPageBaseResp.init(friendPage, FriendAdapter.buildFriend(friendPage.getList(), userList));
    }

    @Override
    public FriendCheckResp check(Long uid, FriendCheckReq request) {
        // 找到自己跟request中uid的好友关系
        List<UserFriend> friendList = userFriendDao.getFriends(uid, request.getUidList());
        Set<Long> friendUidSet = friendList.stream().map(UserFriend::getFriendUid).collect(Collectors.toSet());
        // 判断friendUid是否在自己的好友列表中
        List<FriendCheckResp.FriendCheck> friendCheckList = request.getUidList().stream().map(friendUid -> {
            FriendCheckResp.FriendCheck friendCheck = new FriendCheckResp.FriendCheck();
            friendCheck.setUid(friendUid);
            friendCheck.setIsFriend(friendUidSet.contains(friendUid));
            return friendCheck;
        }).collect(Collectors.toList());
        return new FriendCheckResp(friendCheckList);
    }

    @Override
    @RedissonLock(key = "#uid")
    public void apply(Long uid, FriendApplyReq request) {
        // 是否是好友关系
        UserFriend userFriend = userFriendDao.getByFriend(uid, request.getTargetUid());
        AssertUtil.isEmpty(userFriend, "你们已经是好友啦！");
        // 是否有待审批记录（自己的）
        UserApply selfApproving = userApplyDao.getFriendApproving(uid, RequestHolder.get().getUid());
        if(Objects.nonNull(selfApproving)){
            log.info("已有好友申请记录,uid:{}, targetId:{}", uid, request.getTargetUid());
            return;
        }
        // 是否有待审批记录（别人的）
        UserApply friendApproving = userApplyDao.getFriendApproving(request.getTargetUid(), uid);
        if (Objects.nonNull(friendApproving)) {
            // 如果别人对自己发出申请，自己申请加别人，则直接通过好友申请
            ((FriendService) AopContext.currentProxy()).applyApprove(uid, new FriendApproveReq(friendApproving.getId()));
            return;
        }
        // 申请入库
        UserApply insert = FriendAdapter.buildFriendApply(uid, request);
        userApplyDao.save(insert);
        // 事件
        applicationEventPublisher.publishEvent(new UserApplyEvent(this, insert));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = "#uid")
    public void applyApprove(Long uid, FriendApproveReq request) {
        UserApply apply = userApplyDao.getById(request.getApplyId());
        AssertUtil.isNotEmpty(apply, "不存在申请记录");
        AssertUtil.equal(apply.getTargetId(), uid, "不存在申请记录");
        AssertUtil.equal(apply.getStatus(), WAIT_APPROVAL.getCode(), "已经同意好友申请");
        // 同意好友申请
        userApplyDao.agree(request.getApplyId());
        // 创建好友关系
        creatFriend(uid, apply.getUid());
        // 创建一个聊天房间
        RoomFriend roomFriend = roomService.createFriendRoom(Arrays.asList(uid, apply.getUid()));
        // 发送一条消息，我们已经是好友了，开始聊天吧！
        chatService.sendMsg(MessageAdapter.buildAgreeMsg(roomFriend.getRoomId()), uid);
    }

    @Override
    public PageBaseResp<FriendApplyResp> pageApplyFriend(Long uid, PageBaseReq request) {
        IPage<UserApply> page = userApplyDao.friendApplyPage(uid, request);
        if(CollectionUtils.isEmpty(page.getRecords())){
            return PageBaseResp.empty();
        }
        //将这未读的好友申请设置为已读
        readApply(uid, page);
        return PageBaseResp.init(page, FriendAdapter.buildFriendApplyList(page.getRecords()));
    }

    @Override
    public void deleteFriend(Long uid, Long friendUid) {
        // 删除好友
        List<UserFriend> userFriends = userFriendDao.getUserFriend(uid, friendUid);
        if(CollectionUtils.isEmpty(userFriends)){
            log.info("没有好友关系：{},{}", uid, friendUid);
            return;
        }
        List<Long> friendsId = userFriends.stream().map(UserFriend::getId).collect(Collectors.toList());
        userFriendDao.removeByIds(friendsId);
        // 禁用房间
        roomService.disableFriendRoom(Arrays.asList(uid, friendUid));
    }

    @Override
    public FriendUnreadResp unread(Long targetId) {
        Integer count = userApplyDao.getUnRead(targetId);
        return new FriendUnreadResp(count);
    }

    private void readApply(Long uid, IPage<UserApply> page) {
        List<Long> applyIds = page.getRecords()
                .stream()
                .map(UserApply::getId)
                .collect(Collectors.toList());
        userApplyDao.readApplies(uid, applyIds);
    }

    private void creatFriend(Long uid, Long friendUid) {
        UserFriend userFriend1 = new UserFriend();
        userFriend1.setUid(uid);
        userFriend1.setFriendUid(friendUid);
        UserFriend userFriend2 = new UserFriend();
        userFriend2.setUid(friendUid);
        userFriend2.setFriendUid(uid);
        userFriendDao.saveBatch(Lists.newArrayList(userFriend1, userFriend2));
    }

}
